/**********************************************************************/
/******************************************/
/* A tic-tac-toe board in 3D - like Parker Bros' "Qubic" */
/******************************************/

/* Compile with g++ -o ttt3d ttt3d.cc -I /usr/X11R6/include/ -L /usr/X11R6/lib/ -lglut -lGL -lGLU -lX11 -lXi -lm
 */

#include <math.h>

/* For WINDOWS only
#include <windows.h>
#include <gl\gl.h>
#include <gl\glut.h>
#include <gl\glu.h>
*/

/* For Linux */
#include <GL/gl.h>
#include <GL/glut.h>
#include <GL/glu.h>

void init(void);
void display(void);
void resize(int, int);
void keyboard(unsigned char, int, int);

int main (int argc, char **argv)
{
  glutInit(&argc, argv);
  glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
  glutInitWindowSize(500, 500);
  glutInitWindowPosition(50, 50);
  glutCreateWindow("A 3D Tic-Tac-Toe Board");
  init();
  glutDisplayFunc(display);
  glutKeyboardFunc(keyboard);  /* set keyboard handler */
  /* this time we're going to keep the aspect ratio
     constant by trapping the window resizes */
  glutReshapeFunc(resize); 
  glutMainLoop();
  return 0;
}

void init(void)
{
  glClearColor(0.0, 0.0, 0.0, 0.0);
  //glMatrixMode(GL_PROJECTION);
  glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
  //glLoadIdentity();

  glEnable(GL_DEPTH_TEST); 
  glMatrixMode(GL_MODELVIEW);

  glOrtho(-4.0, 4.0, -4.0, 4.0, 4.0, -4.0);
}

/* draws a circle in a plane parallel to the xy plane */
void drawcircle(GLdouble z, GLdouble center_x, GLdouble center_y,
		GLdouble radius){
  const GLint numlines = 90; // number of lines
  GLdouble pi = acos(-1.0);
  GLdouble angle_increment = 2.0*pi/(GLdouble) numlines;
  glColor3f(1.0, 1.0, 0.0);
  glBegin(GL_POLYGON);
  GLdouble angle = 0.0;
  for (int i = 0; i < numlines;
       i++, angle += angle_increment)
    glVertex3f(radius*cos(angle), radius*sin(angle), z);

} // drawcircle()

void resize(int width, int height)
{
  if (height == 0) height = 1;
  
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  
  /* note we divide our width by our height to get the aspect ratio */
  gluPerspective(45.0, width / height, 1.0, 400.0);
  
  /* set initial position - VERY IMPORTANT to make sure something shows on screen initially! */
  glTranslatef(0.0, 0.0, -2.0);
  
  glMatrixMode(GL_MODELVIEW);
}

void display(void)
{
  int row, col, zindex;
  //glClear(GL_COLOR_BUFFER_BIT);
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  /* draw the game boards */
  glBegin(GL_QUADS); /* Could also use GL_QUAD_STRIP, I suppose! */

  for (zindex = 0; zindex < 4; zindex++){
    if (zindex == 0)
      glColor3f(0.0, 0.0, 1.0);   
    else if (zindex == 1)
      glColor3f(0.0, 1.0, 1.0);   
    else if (zindex == 2)
      glColor3f(1.0, 1.0, 0.0);   
    else
      glColor3f(0.5, 0.7, 0.3);   

    for (row = 0; row < 4; row++){
      for (col = 0; col < 4; col++){	
	glVertex3f(row-2.0, col-2.0, zindex-1.5);
	glVertex3f(row-1.0, col-2.0, zindex-1.5);
	glVertex3f(row-1.0, col-1.0, zindex-1.5);
	glVertex3f(row-2.0, col-1.0, zindex-1.5);
      }/* for; inner */
    }/* for; middle */
  } /* for; outer */       

  glEnd();

  glColor3f(1.0,0.0,0.0);
  /* sphere test
  glutSolidSphere(1.4, 24, 25);
  */

  glutSwapBuffers();
}

void keyboard(unsigned char key, int x, int y)
{
  /* this is the keyboard event handler
     the x and y parameters are the mouse 
     coordintes when the key was struck */
  switch (key)
    {
    case 'R':
      glTranslatef(0.25, 0.0, 0.0);
      break;
    case 'L':
      glTranslatef(-0.25, 0.0, 0.0);
      break;
    case 'n':
      glTranslatef(0.0, 0.0, 0.25);
      break;
    case 'f':
      glTranslatef(0.0, 0.0, -0.25);
      break;
    case 'u':
      glRotatef(-3.0, 1.0, 0.0, 0.0); /* rotate up */
      break;
    case 'd':
      glRotatef(3.0, 1.0, 0.0, 0.0); /* rotate down */
      break;
    case 'l':
      glRotatef(-3.0, 0.0, 1.0, 0.0); /* rotate left */
      break;
    case 'r':
      glRotatef(3.0, 0.0, 1.0, 0.0); /* rotate right */
      break;
    case 'y':
      glRotatef(3.0, 0.0, 0.0, 1.0); /* rotate wrt z axis */
      break;
    case 'z':
      glRotatef(-3.0, 0.0, 0.0, 1.0);
    }
  display(); /* repaint the window */
}
